package com.qp.basics.estivate.jdbc.core;

import com.qp.basics.common.repository.PaginationSupport;
import com.qp.basics.estivate.Database;
import com.qp.basics.estivate.Query;
import com.qp.basics.estivate.ResultSetExtractor;
import com.qp.basics.estivate.Session;
import com.qp.basics.estivate.jdbc.datasource.SessionUtils;
import com.qp.basics.estivate.support.SimpleBeanResultSetExtractor;


import java.io.Serializable;
import java.util.List;
import java.util.Map;

public class EstivateTemplate {

	private Database database;

	public EstivateTemplate(Database database) {
		this.database = database;
	}

	public Object get(final String tableName, final Serializable pk) {
		return executeWithSession(new EstivateCallback() {

			@Override
			public Object doInSession(Session session) {
				return session.get(tableName, pk);
			}
		});
	}

	public Object insert(final String tableName, final Map entity) {
		return executeWithSession(new EstivateCallback() {

			@Override
			public Object doInSession(Session session) {
				return session.insert(tableName, entity);
			}
		});
	}

	public Object save(final String tableName, final Map entity) {
		return executeWithSession(new EstivateCallback() {

			@Override
			public Object doInSession(Session session) {
				return session.merge(tableName, entity);
			}
		});
	}

	public int update(final String tableName, final Map entity) {
		return (Integer) executeWithSession(new EstivateCallback() {

			@Override
			public Object doInSession(Session session) {
				return new Integer(session.update(tableName, entity));
			}
		});
	}

	public int delete(final String tableName, final Serializable pk) {
		return (Integer) executeWithSession(new EstivateCallback() {

			@Override
			public Object doInSession(Session session) {
				return new Integer(session.delete(tableName, pk));
			}
		});
	}

	public Object findByUnique(final String tableName, final String colName,
			final Object v) {
		return executeWithSession(new EstivateCallback() {

			@Override
			public Object doInSession(Session session) {
				return session.findByUnique(tableName, colName, v);
			}
		});
	}

	public Long queryForLong(final String sql, final Object... params) {
		return (Long) executeWithSession(new EstivateCallback() {

			@Override
			public Object doInSession(Session session) {
				return session.queryForLong(sql, params);
			}
		});
	}

	public Object queryForObject(final String sql, final Object... params) {
		return executeWithSession(new EstivateCallback() {

			@Override
			public Object doInSession(Session session) {
				return session.queryForObject(sql, params);
			}
		});
	}

	public String queryForString(final String sql, final Object... params) {
		return (String) executeWithSession(new EstivateCallback() {

			@Override
			public Object doInSession(Session session) {
				return session.queryForString(sql, params);
			}
		});
	}

	public Integer queryForInt(final String sql, final Object... params) {
		return (Integer) executeWithSession(new EstivateCallback() {

			@Override
			public Object doInSession(Session session) {
				return session.queryForInt(sql, params);
			}
		});
	}

	public Map queryForMap(final String sql, final Object... params) {
		return (Map) executeWithSession(new EstivateCallback() {

			@Override
			public Object doInSession(Session session) {
				return session.queryForMap(sql, params);
			}
		});
	}

	public List<Map> queryForList(final String sql, final Object... params) {
		return (List<Map>) executeWithSession(new EstivateCallback() {

			@Override
			public Object doInSession(Session session) {
				return session.queryForList(sql, params);
			}
		});
	}

	/**
	 * 查询指定分页范围的记录。
	 * 
	 * @param sql
	 * @param firstResult
	 * @param maxResults
	 * @param params
	 * @return
	 */
	public List<Map> queryForList(final String sql, final int firstResult,
			final int maxResults, final Object... params) {
		return (List<Map>) executeWithSession(new EstivateCallback() {

			@Override
			public Object doInSession(Session session) {
				Query q = session.createQuery(sql);
				q.setFirstResult(firstResult);
				q.setMaxResults(maxResults);
				if (params != null)
					for (int i = 0; i < params.length; i++) {
						q.setParameter(i + 1, params[i]);
					}
				return q.getResultList();
			}
		});
	}

	public PaginationSupport pagination(final String sql,
										final Object[] params, final int pageNo, final int pageSize) {
		return pagination(sql, params, pageNo, pageSize, null);
	}

	/**
	 * 分页，可以自定义结果集的处理方式。
	 * 
	 * @param sql
	 * @param params
	 * @param pageNo
	 * @param pageSize
	 * @param rse
	 * @return
	 */
	public PaginationSupport pagination(final String sql,
			final Object[] params, final int pageNo, final int pageSize,
			final ResultSetExtractor rse) {
		return (PaginationSupport) executeWithSession(new EstivateCallback() {

			@Override
			public Object doInSession(Session session) {
				Query q = session.createQuery(sql);
				if (params != null) {
					for (int i = 0; i < params.length; i++) {
						q.setParameter(i + 1, params[i]);
					}
				}
				int start = pageNo * pageSize - pageSize;
				q.setFirstResult(start);
				q.setMaxResults(pageSize);
				List<Map> rs = null;
				if (rse != null)
					rs = q.getResultList(rse);
				else
					rs = q.getResultList();
				String countSql = "select count(*) from (" + sql
						+ ") estivate_";
				q.setSql(countSql);
				Number num = (Number) q.getSingleColumnResult();
				int cnt = 0;
				if (num != null)
					cnt = num.intValue();
				PaginationSupport p = new PaginationSupport(rs, cnt, pageNo,
						pageSize);
				return p;
			}
		});
	}

	/**
	 * 分页，列表的元素类型是javaBean。
	 * 
	 * @param sql
	 * @param clazz
	 * @param params
	 * @param pageNo
	 * @param pageSize
	 * @return
	 */
	public PaginationSupport paginationAsBean(final String sql,
			final Class clazz, final Object[] params, final int pageNo,
			final int pageSize) {
		SimpleBeanResultSetExtractor ex = new SimpleBeanResultSetExtractor(
				clazz);
		return pagination(sql, params, pageNo, pageSize, ex);
	}

	/**
	 * 分页。 列表的元素类型是Map。
	 * 
	 * @param sql
	 * @param params
	 * @param pageNo
	 * @param pageSize
	 * @return
	 */
	public PaginationSupport paginationAsMap(final String sql,
			final Object[] params, final int pageNo, final int pageSize) {
		return pagination(sql, params, pageNo, pageSize, null);
	}

	/**
	 * 执行单条sql。
	 * 
	 * @param sql
	 * @param params
	 * @return
	 */
	public int executeUpdate(final String sql, final Object... params) {
		return (Integer) executeWithSession(new EstivateCallback() {
			public Object doInSession(Session session) {
				return new Integer(session.executeUpdate(sql, params));
			}
		});
	}

	/**
	 * 执行多条sql。
	 * 
	 * @param sqls
	 * @return
	 */
	public int[] executeUpdate(final String[] sqls) {
		return (int[]) executeWithSession(new EstivateCallback() {
			public Object doInSession(Session session) {
				return session.executeBatch(sqls);
			}
		});
	}
	public Database getDatabase() {
		return database;
	}
	private Object executeWithSession(EstivateCallback action) {
		Session session = null;
		try {
			session = SessionUtils.getSession(getDatabase());
			Object result = action.doInSession(session);
			return result;
		} finally {
			SessionUtils.releaseSession(session, getDatabase());
		}
	}

}
